#!/usr/bin/python3.6
from lib import *
import requests
import pickle
from typing import List,Dict
logtxt="""
请登录系统:
用户名:"""
logtxt2="密码:"
sess=None
#此处为依赖服务器的功能
connected=False
server_url="http://localhost:8080"
with open("server.txt","r") as f:
    server_url=f.read()

def clear():
    import platform
    if platform.system()=="Windows":
        os.system("cls")
    else:
        os.system("clear")

def login():
    clear()
    global  sess
    while True:
        print(logtxt,end="")
        username=input()
        password=input(logtxt2)
        print("登录中请稍后......")
        sess=WebSeeesion()
        if sess.login(username,password):
            menu1()
        else:
            print("登录失败,请重新登录!")

m1="""
1.查看题目列表
2.查看题目
3.连接服务器
4.查看用户列表
5.查看用户信息
6.查看排行榜
7.我的信息
8.退出
请输入选项:
"""
def print_list():
    clear()
    conttxt="""
请输入选项(1.下一页 2.上一页 3.跳转 4.选择题目 5.返回):
"""
    nowpid=1
    while True:
        clear()
        lst=sess.get_problemList(nowpid)
        for i,l in enumerate(lst):
            print(f"{l.pid}.{l.title}")
        print(f"当前页:{nowpid}\n")
        sele=int(input(conttxt))
        if sele==1:
            nowpid+=1
        elif sele==2:
            if nowpid==1:
                print("已经是第一页")
                continue
            nowpid-=1
        elif sele==3:
            nowpid=int(input("请输入页号:"))
        elif sele==4:
            #进入查看题目界面
            print_problem()
        else:
            return

def print_problem():
    pid = int(input("请输入题目号:"))
    prob=sess.get_problem(pid)
    #打印
    clear()
    text=f"""

{prob.pid}.{prob.title}

{prob.limit}

题目描述
{prob.description}


输入说明
{prob.input_desc}

输出说明
{prob.output_desc}

输入样例
{prob.input_sample}

输出样例
{prob.output_sample}

题目作者
{prob.author}
"""
    print(text)
    #询问
    yn=input("是否开始做题?([y]/n)")
    if yn=="y" or yn=="":
        start(prob)


import os
from os import path
from time import sleep

import platform
def openfile(filename):
    if platform.system()=="Linux":
        os.system(f"xdg-open {filename}")
    elif platform.system()=="Windows":
        os.system(f"start {filename}")
    elif platform.system()=="Darwin":
        os.system(f"open -t {filename}")
    # else:
    #     raise Exception("不支持自动打开")



def print_state(result):
    print(result.state,end="\r")
    if result.state==SubmitResult.CompileErrorState:
        fn=f"./errors/{result.problem.pid}_{result.runid}_compile_error.txt"
        #写入临时文件并打开
        with open(fn,"w") as f:
            f.write(result.compile_error)
            f.close()
        openfile(fn)

def start(prob:Problem):
    #创建提交url模板
    surl=f"{server_url}/submit"
    print("创建文件中......")
    fn=f"./codes/{prob.pid}.cpp"
    if not os.path.exists(fn):
        with open(fn,"w") as f:
            f.write(""" "请在此书写代码"; """)
    openfile(fn)
    #磁盘监控 回车就提交一次 直到不需要update
    while True:
        tyn=input("\n输入q返回，或按enter继续....")
        if tyn=="q" or tyn=="Q":
            break
        #提交
        with open(fn,"r") as f:
            code=f.read()
        res=prob.submit(sess.session,sess.username,code)
        print(res.state,end="\r")
        while res.need_update():
            try:
                if(res.update_state()):
                    # 清行
                    print(" " * 20, end="\r")
                    print_state(res)
                    # 如果AC则提交给服务器
                    if connected and res.state in SubmitResult.AcceptedState:
                        bk=requests.post(surl,data={
                            "runid":res.runid,
                            "username":res.username,
                            "pid":res.problem.pid,
                            "code":res.code
                        })
                        if bk.content==b"0":
                            print(f"\n服务器端提交成功(新题提交)")
                        elif bk.content==b"1":
                            print(f"\n服务器端提交成功(非新题)")
                        else:
                            print(f"\n服务器端提交失败:{bk.content}")
            except Exception as e:
                inp=input("\n提交结果同步错误，是否重新提交?(y/n)")
                if inp=="y":
                    #重新获取res
                    res = prob.submit(sess.session, sess.username, code)
                else:
                    print("\n提交错误!")
                    #停止同步状态 以及重试
                    break
            sleep(1)




def s_connect():
    global connected
    clear()
    print("正在连接服务器......")
    testurl=f"{server_url}/test?username={sess.username}"
    #尝试连接
    res=requests.get(testurl)
    if res.status_code==200:
        if res.content==b"OK":
            print("连接成功!")
            connected=True
            input("按任意键继续......")
            return True
        else:
            print(res.content)
    else:
        print("服务器不存在！")
    print("连接失败!")
    connected=False
    input("按任意键继续......")
    return False

def s_userlist():
    clear()
    if not connected:
        print("请连接服务器!")
        input("按任意键继续......")
        return
    #获取并显示用户列表
    url=f"{server_url}/userlist"
    res=requests.get(url)
    if res.status_code==200:
        obj=pickle.loads(res.content) #type:List[str]
        print("\n\n")
        for i,u in enumerate(obj):
            print(f"{i+1}.{u}")
        print("\n\n")
        input("按任意键返回......")
def show_userinfo(username,showsubmits=False):
    testurl=f"{server_url}/test?username={username}"
    coinurl=f"{server_url}/coin?username={username}"
    sl_url=f"{server_url}/sprob_list/{username}"
    ul_url = f"{server_url}/submit_list/{username}"
    res=requests.get(testurl)
    if res.content!=b"OK":
        print("此用户不存在！")
        input("按任意键继续......")
        return
    #获取信息
    coin=int(requests.get(coinurl).content)
    sl=pickle.loads(requests.get(sl_url).content) #type:List[int]
    #打印
    print(f"用户:{username}")
    print(f"积分:{coin}")
    print("AC列表:")
    for item in sl:
        print(f"{item}",end="\t")
    print("\n")
    #如果显示提交列表
    if showsubmits:
        ul=pickle.loads(requests.get(ul_url).content) #type:List[SubmitResult]
        while True:
            pid=int(input("请输入查询提交列表的题号(-1返回):"))
            if pid==-1:
                break
            pul=[i for i in ul if i.problem.pid == pid]
            for item in pul:
                print(f"Runid:{item.runid} 题目号:{item.problem.pid}")
            #查询代码
            rid=int(input("请输入runid:"))
            if rid not in [i.runid for i in pul]:
                print("本题不存在此次提交")
                continue
            else:
                res={i.runid:i for i in pul}[rid]
                #res为结果对象 通过结果对象获取提交的代码 并调用编辑器打开
                fn=f"{res.problem.pid}_{res.runid}.cpp"
                with open(fn,"w") as f:
                    f.write(res.code)
                openfile(fn)


def s_userinfo():
    clear()
    if not connected:
        print("请连接服务器!")
        input("按任意键继续......")
        return
    #输入用户显示用户的可显示信息 如AC题目列表 积分数等
    un=input("请输入要查询的用户名:")
    show_userinfo(un)
    input("按任意键继续......")

def s_userrank():
    clear()
    if not connected:
        print("请连接服务器!")
        input("按任意键继续......")
        return
    #显示排行榜 按积分排序
    #获取所有用户列表和其的 coin
    ulurl = f"{server_url}/userlist"
    coinurl = "{}/coin?username={}"
    ul=pickle.loads(requests.get(ulurl).content)
    coins={u:int(requests.get(coinurl.format(server_url,u)).content) for u in ul }
    #排序
    sul=sorted(ul,key=lambda x:coins[x],reverse=True)
    #输出
    for i,u in enumerate(sul):
        print(f"{i+1}.{u}")
    input("按任意键继续......")

def s_panel():
    clear()
    if not connected:
        print("请连接服务器!")
        return
    #显示自己的信息
    show_userinfo(sess.username,showsubmits=True)
    input("按任意键继续......")
#主菜单
m1funs=[print_list, print_problem, s_connect, s_userlist, s_userinfo, s_userrank, s_panel, lambda :exit(0)]
def menu1():
    while True:
        clear()
        sele=int(input(m1))
        m1funs[sele-1]()

login()
